package com.yidu.nas.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yidu.nas.api.ICompanyAdminService;
import com.yidu.nas.api.ICompanyService;
import com.yidu.nas.api.ILoginService;
import com.yidu.nas.api.IUserService;
import com.yidu.nas.component.core.constant.CacheConstants;
import com.yidu.nas.component.core.text.Convert;
import com.yidu.nas.component.core.utils.ip.IpUtils;
import com.yidu.nas.component.redis.service.RedisDataService;
import com.yidu.nas.component.security.service.TokenService;
import com.yidu.nas.component.security.utils.SecurityUtils;
import com.yidu.nas.domain.ProjectMember;
import com.yidu.nas.domian.model.Company;
import com.yidu.nas.domian.model.LoginUser;
import com.yidu.nas.domian.model.User;
import com.yidu.nas.domian.request.user.UserQuery;
import com.yidu.nas.enums.BizCodeEnums;
import com.yidu.nas.enums.CompanyVersionTypeEnum;
import com.yidu.nas.mapper.UserMapper;
import com.yidu.nas.user.api.IUserRoleService;
import com.yidu.nas.user.enums.UserRoleEnum;
import com.yidu.nas.user.enums.UserStateEnum;
import com.yidu.nas.user.vo.UserRoleVO;
import com.yidu.nas.user.vo.UserVO;
import com.yidu.nas.utils.ParamAssertUtil;
import com.yidu.nas.utils.UserRoleUtils;
import com.yidu.nas.web.result.ResultForm;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 登录service实现类
 *
 * @Author ws
 */
@Service
public class LoginServiceImpl implements ILoginService {

    private static final Log log = LogFactory.get();

    @Resource
    private RedisDataService redisDataService;

    @Resource
    private IUserService userService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ICompanyAdminService companyAdminService;

    @Resource
    private IUserRoleService userRoleService;

    @Resource
    private ICompanyService companyService;

    @Resource
    private TokenService tokenService;

    /**
     * 用户登录
     *
     * @param username 用户账号
     * @param password 密码
     * @return {@link ResultForm<LoginUser> }
     * @author yangshuai
     * @time 2024/7/5 14:00
     */
    @Override
    public ResultForm<LoginUser> login(String sysCompanyCode, String username, String password) {

        if (StrUtil.isBlank(username)) {
            return ResultForm.fail("用户名不能为空");
        }

        if (StrUtil.isBlank(password)) {
            return ResultForm.fail("密码不能为空");
        } else {
            password = StrUtil.trimToEmpty(password);
        }

        // sysCompanyCode可以为null，如果根据用户名查出多条记录，则返回错误，提示要输入sysCompanyCode，此为兼容模式
        List<User> userList = userMapper.listByUserName(sysCompanyCode, username);
        if (ObjectUtil.isEmpty(userList)) {
            return ResultForm.fail("登录账号：" + username + " 不存在");
        }

        if (userList.size() > 1) {
            log.warn("登录用户：" + username + "存在多个用户，公司代码为" + sysCompanyCode);
            return ResultForm.fail("登录名：" + username + "，存在多个用户记录");
        }
        User user = userList.get(0);
        sysCompanyCode = user.getSysCompanyCode();

        // IP黑名单校验
        String blackStr = Convert.toStr(redisDataService.get(sysCompanyCode, CacheConstants.SYS_LOGIN_BLACKIPLIST));
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
            return ResultForm.fail("您的访问IP暂不能登录");
        }

        // 校验账号状态
        if (UserStateEnum.DISABLE.getCode().equals(user.getState())) {
            return ResultForm.fail("您的账号已停用");
        }

        // 校验密码
        String errorMsg = validatePassword(user, password);
        if (StrUtil.isNotBlank(errorMsg)) {
            return ResultForm.fail(errorMsg);
        }

        // 封装登录用户信息
        LoginUser loginUser = BeanUtil.copyProperties(user, LoginUser.class);
        loginUser.setUserId(user.getId());
        loginUser.setIpAddr(IpUtils.getIpAddr());

        // 填充用户角色列表
        fillRoleList(loginUser);

        // 填充所属公司信息，包括公司名称和公司logo url
        fillCompanyInfo(loginUser);

        // 判断如果是试用版，是否到期
        if (CompanyVersionTypeEnum.TRIAL.getCode().equals(loginUser.getVersionType()) && LocalDateTime.now().isAfter(loginUser.getLicenseEndTime())) {
            return ResultForm.fail(BizCodeEnums.TRIAL_EXPIRED.getCode(), null,BizCodeEnums.TRIAL_EXPIRED.getMsg());
        }

        // 生成token
        tokenService.createToken(loginUser);

        // 获取用户拥有管理员权限的公司id
        List<String> adminAuthCompanyIdList = companyAdminService.getAdminAuthCompanyIds(sysCompanyCode, loginUser.getUserId());
        if (CollectionUtil.isNotEmpty(adminAuthCompanyIdList)) {
            loginUser.setAdminCompanyList(adminAuthCompanyIdList);
        }

        // 更新登录时间和ip
        updateLoginTimeAndIP(loginUser);

        // 填充临时属性，为了兼容旧版本
        fillTempProperty(loginUser);

        return ResultForm.success(loginUser);
    }

    /**
     * 填充临时属性，为了兼容前端旧版本
     * @param loginUser 登录用户对象
     * @author yangshuai
     * @time 2024/9/11 10:54
     */
    public static void fillTempProperty(LoginUser loginUser) {
        if (ObjectUtil.isNotEmpty(loginUser)) {
            loginUser.setAccess_token(loginUser.getAccessToken());
            loginUser.setSftp_password(loginUser.getSftpPassword());
            loginUser.setSftp_user_name(loginUser.getSftpUserName());
            loginUser.setExpires_in(loginUser.getExpireTimestamp());
            loginUser.setInitial_pwd_flag(loginUser.getInitialPwdFlag());
            if (ObjectUtil.isNotEmpty(loginUser.getUserRoleMap())) {
                if (loginUser.getUserRoleMap().containsKey(UserRoleEnum.KNOWLEDGE_ADMIN.getCode())) {
                    loginUser.setIs_knowledge_admin(Boolean.TRUE);
                } else {
                    loginUser.setIs_knowledge_admin(Boolean.FALSE);
                }
            }
        }
    }

    /**
     * 填充公司信息
     * @param loginUser 登录对象
     * @author yangshuai
     * @time 2024/9/11 09:15
     */
    private void fillCompanyInfo(LoginUser loginUser) {
        if (ObjectUtil.isNotEmpty(loginUser)) {
            LambdaQrapperWrapperCompany> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ComueryWpany::getSysCompanyCode, loginUser.getSysCompanyCode()).eq(Company::getId, loginUser.getCompanyId()).eq(Company::getDelFlag, 0);
//查询条件
            Company company = companyService.getOne(queryWrapper);
            if (ObjectUtil.isNotEmpty(company)) {
                loginUser.setCompanyName(company.getName());
                loginUser.setCompanyLogo(company.getLogo());
                loginUser.setVersionType(company.getVersionType());
                loginUser.setLicenseEndTime(company.getLicenseEndTime());
            }
        }
    }

    /**
     * 更新登录时间和ip
     * @param loginUser 登录用户
     * @author yangshuai
     * @time 2024/9/10 17:49
     */
    private void updateLoginTimeAndIP(LoginUser loginUser) {
        if (ObjectUtil.isNotEmpty(loginUser)) {
            LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();

            String ipAddr = StrUtil.isBlank(IpUtils.getIpAddr()) ? "" : IpUtils.getIpAddr(); //获取当前的ip地址
            updateWrapper.eq(User::getId, loginUser.getUserId());                           //设置更新条件
            updateWrapper.set(User::getLoginIp, ipAddr);                                   //更新IP
            updateWrapper.set(User::getLoginDate, new Date());                            //更新ID
            userService.update(updateWrapper);
        }
    }

    /**
     * 为loginUser对象填充角色列表
     * @param loginUser 登录用户对象
     * @author yangshuai
     * @time 2024/9/10 17:41
     */
    private void fillRoleList(LoginUser loginUser) {
        if (ObjectUtil.isEmpty(loginUser)) {
            return;
        }

        List<UserRoleVO> roleList = userRoleService.listRoleByUserId(loginUser.getSysCompanyCode(), loginUser.getUserId());
        if (ObjectUtil.isNotEmpty(roleList)) {
            Set<String> roleKeySet = roleList.stream()
                    .map(UserRoleVO::getRoleKey)
                    .collect(Collectors.toSet());

            loginUser.setRoleKeyList(new ArrayList<>(roleKeySet));

            // 组装用户角色map，这里是完整的角色信息
            Map<String, Object> userRoleMap = UserRoleUtils.buildUserRoleMap(roleList);
            loginUser.setUserRoleMap(userRoleMap);
        }
    }

    /**
     * 校验密码
     *3
     * @param user     用户对象
     * @param password 密码
     * @return {@link String }
     * @author yangshuai
     * @time 2024/9/23 10:59
     */
    public String validatePassword(User user, String password) {
        try {
            String username = user.getUserName();
            if (StrUtil.isBlank(username)) {
                return "用户名不能为空";
            }

            if (StrUtil.isBlank(password)) {
                return "密码不能为空";
            }
//
            String sysCompanyCode = user.getSysCompanyCode();
//            // 查询token记录
//            TokenInfo tokenInfo = (TokenInfo) redisDataService.get(sysCompanyCode, getCacheKey(username));
//
//            int retryCount = 0;
//            if (tokenInfo != null) {
//                retryCount = Integer.parseInt(tokenInfo.getValue());
//            }
//
//            if (retryCount >= CacheConstants.PASSWORD_MAX_RETRY_COUNT) {
//                return String.format("密码输入错误%s次，帐户锁定%s分钟", CacheConstants.PASSWORD_MAX_RETRY_COUNT, CacheConstants.PASSWORD_LOCK_TIME);
//            }

            if (!matches(user, password)) {
//                retryCount = retryCount + 1;

                // 保存token
//                redisDataService.saveToken(sysCompanyCode, getCacheKey(username), retryCount, CacheConstants.PASSWORD_LOCK_TIME, TimeUnit.MINUTES);
                return "用户名密码不匹配";
            } else {
                clearLoginRecordCache(sysCompanyCode, username);
            }
            return null;
        } catch (Exception e) {
            return "密码校验失败";
        }

    }

    public boolean matches(User user, String rawPassword) {
        ParamAssertUtil.notNull(user, "user不能为空");
        ParamAssertUtil.hasText(rawPassword, "rawPassword不能为空");
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
    }


    public void clearLoginRecordCache(String sysCompanyCode, String loginName) {
        // mysql模拟redis缓存数据库
        if (redisDataService.hasKey(sysCompanyCode, getCacheKey(loginName))) {
            redisDataService.delete(sysCompanyCode, getCacheKey(loginName));
        }
    }

    /**
     * 登录账户密码错误次数缓存键名
     *
     * @param username 用户名
     * @return 缓存键key
     */
    private String getCacheKey(String username) {
        return CacheConstants.PWD_ERR_CNT_KEY + username;
    }
}
